/*
 * Copyright (c) 2006-2011, Petr Panteleyev
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *    3. The name of the author may not be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.panteleyev.blogclient;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.util.ArrayList;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.SwingUtilities;

import org.jdesktop.swingx.JXBusyLabel;
import org.panteleyev.blogclient.events.UserProfilesUpdatedEvent;
import org.panteleyev.blogclient.profwizard.NewProfileWizard;
import org.panteleyev.swing.BasicDialog;
import org.panteleyev.swing.OkCancelButtonPanel;
import org.panteleyev.swing.SimpleComboBoxModel;
import org.panteleyev.swing.SwingFactory;
import org.panteleyev.swing.WindowManager;

public final class LoginDialog extends BasicDialog<BloggerFrame<?>> {
    private volatile Thread     loginThread = null;
    private AccountListModel    listModel;
    private boolean             loggedIn = false;

    // Controls
    private JXBusyLabel         busyLabel = new JXBusyLabel(new Dimension(16, 16));
    private JComboBox<String>   loginEdit = new JComboBox<>();
    private JPasswordField      passwordEdit;
    private JCheckBox           storePasswdCheck;
    private JCheckBox           offlineModeCheck;
    private OkCancelButtonPanel okCancelPanel;
    private AbstractAction      newProfileAction;

    private final class AccountListModel extends SimpleComboBoxModel<String> {
        private ArrayList<UserProfile<?>> available;

        public AccountListModel() {
            fireListDataChanged();
        }

        @Override
        public void fireListDataChanged() {
            ArrayList<UserProfile<?>> list = UserProfileManager.getProfiles();
            available = new ArrayList<>(list.size());

            for (UserProfile<?> prof : list) {
                if (!prof.isConnected()) {
                    available.add(prof);
                }
            }

            super.fireListDataChanged();
        }

        @Override
        public String getElementAt(int arg0) {
            return available.get(arg0).getName();
        }

        @Override
        public int getSize() {
            return available.size();
        }
    }

    /**
     * Creates new form LoginDialog
     * @param parent
     */
    public LoginDialog(BloggerFrame<?> parent) {
        super(parent);
        setTitle(L10N.LOGIN_DIALOG_TITLE.s());

        initComponents();

        if (UserProfileManager.getDefaultProfileName() != null) {
            loginEdit.setSelectedItem(UserProfileManager.getDefaultProfileName());
            int index = loginEdit.getSelectedIndex();
            if (index == -1) {
                loginEdit.setSelectedIndex(0);
            }
        }
    }

    private void initComponents() {
        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));

        JLabel loginLabel = new JLabel(L10N.LOGIN_DIALOG_NAME_LABEL.s());
        JLabel passwdLabel = new JLabel(L10N.LOGIN_DIALOG_PASSWORD_LABEL.s());

        SwingFactory.setCommonPreferredSize(loginLabel, passwdLabel);

        JPanel panel = SwingFactory.createPanel(BorderFactory.createEmptyBorder(5,5,5,5),
            SwingFactory.LAYOUT.BOX_Y,
            SwingFactory.createPanel(null, SwingFactory.LAYOUT.BOX_X,
                loginLabel,
                Box.createHorizontalStrut(3),
                loginEdit,
                Box.createHorizontalStrut(5),
                busyLabel,
                Box.createHorizontalStrut(5)
            ),
            Box.createVerticalStrut(5),
            SwingFactory.createPanel(null, SwingFactory.LAYOUT.BOX_X,
                passwdLabel,
                Box.createHorizontalStrut(3),
                passwordEdit = new JPasswordField()
            ),
            Box.createVerticalStrut(5),
            storePasswdCheck = new JCheckBox(L10N.LOGIN_DIALOG_REMEMBER_PASSWORD_CHECKBOX.s()),
            Box.createVerticalStrut(3),
            offlineModeCheck = new JCheckBox("Offline")
        );
        getContentPane().add(panel);
        SwingFactory.setAlignmentX(panel, LEFT_ALIGNMENT);

        newProfileAction = new AbstractAction(L10N.LOGIN_DIALOG_CREATE_PROFILE_ACTION.s()) {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                onNewProfile();
            }
        };

        panel = SwingFactory.createPanel(BorderFactory.createEmptyBorder(5,5,5,5),
            SwingFactory.LAYOUT.BOX_X,
            new JButton(newProfileAction),
            Box.createHorizontalGlue(),
            okCancelPanel = new OkCancelButtonPanel(this, BorderFactory.createEmptyBorder(0, 0, 0, 0))
        );
        getContentPane().add(panel);

        SwingFactory.setAlignmentX(getContentPane(), LEFT_ALIGNMENT);

        loginEdit.setModel(listModel = new AccountListModel());
        loginEdit.addActionListener(new java.awt.event.ActionListener() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onProfileSelected();
            }
        });

        pack();
    }

    public String getProfileName() { return (String)loginEdit.getSelectedItem(); }
    public UserProfile<?> getProfile() { return UserProfileManager.getProfile(getProfileName()); }
    public String getPassword() { return new String(this.passwordEdit.getPassword()); }
    public boolean getStorePasswd() { return this.storePasswdCheck.isSelected(); }
    public boolean getOfflineMode() { return offlineModeCheck.isSelected(); }
    public boolean isLoggedIn() { return loggedIn; }

    @Override
    public void onOk() {
        String profName = getProfileName();
        String newPasswd = getPassword();
        final boolean store = getStorePasswd();
        final boolean offline = getOfflineMode();

        final UserProfile<?> prof = UserProfileManager.getProfile(profName);
        if (prof.isConnected()) {
            super.onOk();
        } else {
            if (prof.getStorePasswd()) {
                if (prof.getHPasswd().equals(newPasswd)) {
                    prof.setPasswdTemp(prof.getPassword());
                } else {
                    prof.setPasswdTemp(newPasswd);
                }
            } else {
                prof.setPasswdTemp(newPasswd);
            }

            loginThread = new Thread() {
                public void run() {
                    loggedIn = prof.login(store, offline);
                    if (loggedIn) {
                        prof.setStorePasswd(store);
                        if (store) {
                            prof.applyPasswdTemp();
                        } else {
                            prof.setPassword("");
                        }
                        UserProfileManager.saveProfiles();
                    }

                    finishLogin(loggedIn);
                }
            };

            startLogin();
            loginThread.start();
        }
    }

    private void startLogin() {
        busyLabel.setBusy(true);
        okCancelPanel.getOkButton().setEnabled(false);
        newProfileAction.setEnabled(false);
        loginEdit.setEnabled(false);
        passwordEdit.setEnabled(false);
        storePasswdCheck.setEnabled(false);
        offlineModeCheck.setEnabled(false);
    }

    private void finishLogin(boolean success) {
        loginThread = null;
        if (success) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    LoginDialog.super.onOk();
                }
            });
        } else {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    busyLabel.setBusy(false);
                    okCancelPanel.getOkButton().setEnabled(true);
                    newProfileAction.setEnabled(true);
                    loginEdit.setEnabled(true);
                    passwordEdit.setEnabled(true);
                    storePasswdCheck.setEnabled(true);
                    offlineModeCheck.setEnabled(true);
                }
            });
        }
    }

    @Override
    public void onCancel() {
        if (loginThread == null) {
            super.onCancel();
        } else {
            loginThread.interrupt();
        }
    }

    private void onNewProfile() {
        NewProfileWizard dial = new NewProfileWizard(null);
        if (dial.showDialog()) {
            listModel.fireListDataChanged();
            WindowManager.sendApplicationEvent(new UserProfilesUpdatedEvent(this));
        }
    }

    public void autoLogin(UserProfile<?> prof) {
        loginEdit.setSelectedItem(prof.getName());

        if (prof.getStorePasswd()) {
            onOk();
        }

        showDialog();
    }

    private void onProfileSelected() {
        String profName = (String)this.loginEdit.getSelectedItem();
        if (profName != null) {
            UserProfile<?> prof = UserProfileManager.getProfile(profName);
            if (prof != null) {
                boolean flickr = prof.getProfileType() == UserProfileType.FLICKR;
                passwordEdit.setEnabled(!flickr);
                storePasswdCheck.setEnabled(!flickr);
                offlineModeCheck.setEnabled(!flickr);

                boolean store = prof.getStorePasswd();

                if (store) {
                    passwordEdit.setText(prof.getHPasswd());
                } else {
                    passwordEdit.setText("");
                }

                storePasswdCheck.setSelected(store);
            }
        }
    }

}
